home *** CD-ROM | disk | FTP | other *** search
/ Clickx 115 / Clickx 115.iso / software / tools / windows / tails-i386-0.16.iso / live / filesystem.squashfs / usr / bin / mat-gui < prev    next >
Encoding:
Text File  |  2012-05-30  |  21.2 KB  |  581 lines

  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*
  3.  
  4. '''
  5.     Metadata anonymisation toolkit - GUI edition
  6. '''
  7.  
  8. import gtk
  9. import gobject
  10.  
  11. import gettext
  12. import locale
  13. import logging
  14. import os
  15. import sys
  16. import mimetypes
  17. import xml.sax
  18. import urllib2
  19.  
  20. from lib import mat
  21. from lib import strippers
  22.  
  23.  
  24. logging.basicConfig(level=mat.LOGGING_LEVEL)
  25.  
  26.  
  27. class CFile(object):
  28.     '''
  29.         Contain the "parser" class of the file "filename"
  30.         This class exist just to be "around" my parser.Generic_parser class,
  31.         since the gtk.ListStore does not accept it.
  32.     '''
  33.     def __init__(self, filename, backup, add2archive):
  34.         try:
  35.             self.file = mat.create_class_file(filename, backup, add2archive)
  36.         except:
  37.             self.file = None
  38.  
  39.  
  40. class GUI:
  41.     '''
  42.         Main GUI class
  43.     '''
  44.     def __init__(self):
  45.         # Preferences
  46.         self.force = False
  47.         self.backup = True
  48.         self.add2archive = True
  49.  
  50.         # Main window
  51.         self.window = gtk.Window()
  52.         self.window.set_title('Metadata Anonymisation Toolkit')
  53.         self.window.connect('destroy', gtk.main_quit)
  54.         self.window.set_default_size(800, 600)
  55.         self.logo = mat.get_sharedir('logo.png')
  56.         icon = gtk.gdk.pixbuf_new_from_file_at_size(self.logo, 50, 50)
  57.         self.window.set_icon(icon)
  58.  
  59.         self.accelerator = gtk.AccelGroup()
  60.         self.window.add_accel_group(self.accelerator)
  61.  
  62.         vbox = gtk.VBox()
  63.         self.window.add(vbox)
  64.  
  65.         menubar = self.__create_menu()
  66.         toolbar = self.__create_toolbar()
  67.         content = gtk.ScrolledWindow()
  68.         content.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
  69.         vbox.pack_start(menubar, False, True, 0)
  70.         vbox.pack_start(toolbar, False, True, 0)
  71.         vbox.pack_start(content, True, True, 0)
  72.  
  73.         # parser.class - name - path - type - cleaned
  74.         self.liststore = gtk.ListStore(object, str, str, str, str, str)
  75.  
  76.         self.treeview = gtk.TreeView(model=self.liststore)
  77.         self.treeview.set_search_column(1)  # filename column is searchable
  78.         self.treeview.set_rules_hint(True)  # alternate colors for rows
  79.         self.treeview.set_rubber_banding(True)  # mouse selection
  80.         self.treeview.connect("key_press_event", self.treeview_keyboard_event)
  81.         self.treeview.connect('row-activated', self.__popup_metadata)
  82.         self.treeview.connect('drag_data_received',
  83.                 self.__on_drag_data_received)
  84.         self.treeview.drag_dest_set(gtk.DEST_DEFAULT_MOTION |
  85.                 gtk.DEST_DEFAULT_HIGHLIGHT | gtk.DEST_DEFAULT_DROP,
  86.                 [('text/uri-list', 0, 80), ], gtk.gdk.ACTION_COPY)
  87.         self.__add_columns()
  88.         self.selection = self.treeview.get_selection()
  89.         self.selection.set_mode(gtk.SELECTION_MULTIPLE)
  90.  
  91.         content.add(self.treeview)
  92.  
  93.         self.statusbar = gtk.Statusbar()
  94.         self.statusbar.push(1, _('Ready'))
  95.         vbox.pack_start(self.statusbar, False, False, 0)
  96.  
  97.         self.window.show_all()
  98.  
  99.     def __create_toolbar(self):
  100.         '''
  101.             Returns a vbox object, which contains a toolbar with buttons
  102.         '''
  103.         toolbar = gtk.Toolbar()
  104.  
  105.         toolbutton = gtk.ToolButton(gtk.STOCK_ADD)
  106.         toolbutton.set_label(_('Add'))
  107.         toolbutton.connect('clicked', self.__add_files)
  108.         toolbutton.set_tooltip_text(_('Add files'))
  109.         toolbar.add(toolbutton)
  110.  
  111.         toolbutton = gtk.ToolButton(gtk.STOCK_CLEAR)
  112.         toolbutton.set_label(_('Clean'))
  113.         toolbutton.connect('clicked', self.__process_files, self.__mat_clean)
  114.         toolbutton.set_tooltip_text(_('Clean selected files'))
  115.         toolbar.add(toolbutton)
  116.  
  117.         toolbutton = gtk.ToolButton(gtk.STOCK_FIND)
  118.         toolbutton.set_label(_('Check'))
  119.         toolbutton.connect('clicked', self.__process_files, self.__mat_check)
  120.         toolbutton.set_tooltip_text(_('Check selected files for harmful meta'))
  121.         toolbar.add(toolbutton)
  122.  
  123.         toolbutton = gtk.ToolButton(stock_id=gtk.STOCK_QUIT)
  124.         toolbutton.set_label(_('Quit'))
  125.         toolbutton.connect('clicked', gtk.main_quit)
  126.         toolbar.add(toolbutton)
  127.  
  128.         vbox = gtk.VBox(spacing=3)
  129.         vbox.pack_start(toolbar, False, False, 0)
  130.         return vbox
  131.  
  132.     def __add_columns(self):
  133.         '''
  134.             Create the columns, and add them to the treeview
  135.         '''
  136.         colname = [_('Path'), _('Filename'), _('Mimetype'), _('State'),
  137.             _('Cleaned file')]
  138.  
  139.         for i, j in enumerate(colname, 1):
  140.             filename_column = gtk.CellRendererText()
  141.             column = gtk.TreeViewColumn(j, filename_column, text=i)
  142.             column.set_sort_column_id(i)
  143.             column.set_resizable(True)  # column is resizeable
  144.             self.treeview.append_column(column)
  145.  
  146.     def __create_menu_item(self, name, func, menu, pix, shortcut):
  147.         '''
  148.             Create a MenuItem() like Preferences, Quit, Add, Clean, ...
  149.         '''
  150.         item = gtk.ImageMenuItem()
  151.         if shortcut:
  152.             key, mod = gtk.accelerator_parse(shortcut)
  153.             item.add_accelerator('activate', self.accelerator,
  154.                 key, mod, gtk.ACCEL_VISIBLE)
  155.         picture = gtk.Image()
  156.         picture.set_from_stock(pix, gtk.ICON_SIZE_MENU)
  157.         item.set_image(picture)
  158.         item.set_label('_' + name)
  159.         item.set_use_underline(True)
  160.         item.connect('activate', func)
  161.         menu.append(item)
  162.  
  163.     def __create_sub_menu(self, name, menubar):
  164.         '''
  165.             Create a submenu like File, Edit, Clean, ...
  166.         '''
  167.         submenu = gtk.Menu()
  168.         menuitem = gtk.MenuItem()
  169.         menuitem.set_submenu(submenu)
  170.         menuitem.set_label('_' + name)
  171.         menuitem.set_use_underline(True)
  172.         menubar.append(menuitem)
  173.         return submenu
  174.  
  175.     def __create_menu(self):
  176.         '''
  177.             Return a MenuBar
  178.         '''
  179.         menubar = gtk.MenuBar()
  180.  
  181.         file_menu = self.__create_sub_menu(_('Files'), menubar)
  182.         self.__create_menu_item(_('Add files'), self.__add_files, file_menu,
  183.             gtk.STOCK_ADD, '<Control>O')
  184.         self.__create_menu_item(_('Quit'), gtk.main_quit, file_menu,
  185.             gtk.STOCK_QUIT, '<Control>Q')
  186.  
  187.         edit_menu = self.__create_sub_menu(_('Edit'), menubar)
  188.         self.__create_menu_item(_('Clear the filelist'),
  189.             lambda x: self.liststore.clear(), edit_menu, gtk.STOCK_REMOVE,
  190.             None)
  191.         self.__create_menu_item(_('Preferences'), self.__preferences,
  192.                 edit_menu, gtk.STOCK_PREFERENCES, '<Control>P')
  193.  
  194.         process_menu = self.__create_sub_menu(_('Process'), menubar)
  195.         item = gtk.ImageMenuItem()
  196.         key, mod = gtk.accelerator_parse('<Control>L')
  197.         item.add_accelerator('activate', self.accelerator,
  198.             key, mod, gtk.ACCEL_VISIBLE)
  199.         picture = gtk.Image()
  200.         picture.set_from_stock(gtk.STOCK_CLEAR, gtk.ICON_SIZE_MENU)
  201.         item.set_image(picture)
  202.         item.set_label(_('Clean'))
  203.         item.connect('activate', self.__process_files, self.__mat_clean)
  204.         process_menu.append(item)
  205.  
  206.         item = gtk.ImageMenuItem()
  207.         key, mod = gtk.accelerator_parse('<Control>h')
  208.         item.add_accelerator('activate', self.accelerator,
  209.             key, mod, gtk.ACCEL_VISIBLE)
  210.         picture = gtk.Image()
  211.         picture.set_from_stock(gtk.STOCK_FIND, gtk.ICON_SIZE_MENU)
  212.         item.set_image(picture)
  213.         item.set_label(_('Check'))
  214.         item.connect('activate', self.__process_files, self.__mat_check)
  215.         process_menu.append(item)
  216.  
  217.         help_menu = self.__create_sub_menu(_('Help'), menubar)
  218.         self.__create_menu_item(_('Supported formats'), self.__supported,
  219.             help_menu, gtk.STOCK_INFO, False)
  220.         self.__create_menu_item(_('About'), self.__about, help_menu,
  221.                 gtk.STOCK_ABOUT, False)
  222.  
  223.         return menubar
  224.  
  225.     def treeview_keyboard_event(self, widget, event):
  226.         '''
  227.             Remove selected files from the treeview
  228.             when the use hit the 'suppr' key
  229.         '''
  230.         if gtk.gdk.keyval_name(event.keyval) == "Delete":
  231.             rows = []
  232.             self.selection.selected_foreach(
  233.                     lambda model, path, iter: rows.append(iter))
  234.             [self.liststore.remove(i) for i in rows]
  235.  
  236.     def __add_files(self, button):
  237.         '''
  238.             Add the files chosed by the filechoser ("Add" button)
  239.         '''
  240.         chooser = gtk.FileChooserDialog(title=_('Choose files'),
  241.             parent=self.window, action=gtk.FILE_CHOOSER_ACTION_OPEN,
  242.             buttons=(gtk.STOCK_OK, 0, gtk.STOCK_CANCEL, 1))
  243.         chooser.set_default_response(0)
  244.         chooser.set_select_multiple(True)
  245.  
  246.         all_filter = gtk.FileFilter()  # filter that shows all files
  247.         all_filter.set_name(_('All files'))
  248.         all_filter.add_pattern('*')
  249.         chooser.add_filter(all_filter)
  250.  
  251.         supported_filter = gtk.FileFilter()
  252.         # filter that shows only supported formats
  253.         [supported_filter.add_mime_type(i) for i in strippers.STRIPPERS.keys()]
  254.         supported_filter.set_name(_('Supported files'))
  255.         chooser.add_filter(supported_filter)
  256.  
  257.         response = chooser.run()
  258.  
  259.         if response is 0:  # gtk.STOCK_OK
  260.             filenames = chooser.get_filenames()
  261.             task = self.populate(filenames)
  262.             gobject.idle_add(task.next)  # asynchrone processing
  263.         chooser.destroy()
  264.  
  265.     def populate(self, filenames):
  266.         '''
  267.             Append selected files by add_file to the self.liststore
  268.         '''
  269.         not_supported = []
  270.         for filename in filenames:  # filenames : all selected files/folders
  271.             if os.path.isdir(filename):  # if "filename" is a directory
  272.                 for root, dirs, files in os.walk(filename):
  273.                     for item in files:
  274.                         path_to_file = os.path.join(root, item)
  275.                         if self.__add_file_to_treeview(path_to_file):
  276.                             not_supported.append(item)
  277.             else:  # filename is a regular file
  278.                 if self.__add_file_to_treeview(filename):
  279.                     not_supported.append(filename)
  280.             yield True
  281.         if not_supported:
  282.             self.__popup_non_supported(not_supported)
  283.         yield False
  284.  
  285.     def __add_file_to_treeview(self, filename):
  286.         '''
  287.             Add a file to the list if it's format is supported
  288.         '''
  289.         if not os.path.isfile(filename):
  290.             # if filename does not exist
  291.             return False
  292.  
  293.         cf = CFile(filename, self.backup, self.add2archive)
  294.         if cf.file is not None:  # if the file is supported by the mat
  295.             self.liststore.append([cf, os.path.dirname(cf.file.filename) + os.path.sep,
  296.                 cf.file.basename, cf.file.mime, _('unknow'), 'None'])
  297.             return False
  298.         else:
  299.             return True
  300.  
  301.     def __popup_metadata(self, widget, row, col):
  302.         '''
  303.             Popup that display on double-clic
  304.             metadata from a file
  305.         '''
  306.         label = '<b>%s</b>\'s metadatas:\n' % self.liststore[row][1]
  307.         meta = ''
  308.         if self.liststore[row][4] == _('Clean') or\
  309.                 self.liststore[row][0].file.is_clean():
  310.             meta = 'No metadata found'
  311.             self.liststore[row][4] = _('Clean')
  312.         else:
  313.             self.liststore[row][4] = _('Dirty')
  314.             iterator = self.liststore[row][0].file.get_meta().iteritems()
  315.             for i, j in iterator:
  316.                 name = '-<b>' + str(i) + '</b> : '
  317.                 meta += (name + str(j) + '\n')
  318.  
  319.         w = gtk.MessageDialog(self.window,
  320.                 gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
  321.                 gtk.MESSAGE_INFO, gtk.BUTTONS_CLOSE, label)
  322.         w.set_resizable(True)
  323.         w.set_size_request(400, 300)
  324.         scrolled_window = gtk.ScrolledWindow()
  325.         scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
  326.         w.vbox.pack_start(scrolled_window, True, True, 0)
  327.         content = gtk.Label(meta)
  328.         content.set_selectable(True)
  329.         content.set_alignment(0, 0)
  330.         content.set_use_markup(True)
  331.         scrolled_window.add_with_viewport(content)
  332.         w.set_markup(label)
  333.         w.show_all()
  334.         click = w.run()
  335.         if click:
  336.             w.destroy()
  337.  
  338.     def __popup_non_supported(self, filelist):
  339.         '''
  340.             Popup that warn the user about the unsupported files
  341.             that he want to process
  342.         '''
  343.         dialog = gtk.Dialog(title=_('Not-supported'), parent=self.window,
  344.                 flags=0, buttons=(gtk.STOCK_OK, 0))
  345.         vbox = gtk.VBox(spacing=5)
  346.         dialog.get_content_area().pack_start(vbox, True, True, 0)
  347.         store = gtk.ListStore(str, str)
  348.  
  349.         # append filename - mimetype to the store
  350.         #FIXME : I'm ugly
  351.         for item in filelist:
  352.             mime = mimetypes.guess_type(item)[0]
  353.             if mime:
  354.                 store.append([item, mime])
  355.             else:
  356.                 store.append([item, 'unknown'])
  357.  
  358.         treeview = gtk.TreeView(store)
  359.         vbox.pack_start(treeview, True, True, 0)
  360.  
  361.         #create column
  362.         rendererText = gtk.CellRendererText()
  363.         column = gtk.TreeViewColumn(_('Filename'), rendererText, text=0)
  364.         treeview.append_column(column)
  365.         column = gtk.TreeViewColumn(_('Mimetype'), rendererText, text=1)
  366.         treeview.append_column(column)
  367.  
  368.         dialog.show_all()
  369.         click = dialog.run()
  370.         if click is 0:  # Ok button
  371.             dialog.destroy()
  372.  
  373.     def __about(self, button):
  374.         '''
  375.             About popup
  376.         '''
  377.         w = gtk.AboutDialog()
  378.         w.set_authors(['Julien (jvoisin) Voisin', ])
  379.         w.set_artists(['Marine Beno├«t', ])
  380.         w.set_copyright('GNU Public License v2')
  381.         w.set_comments(_('This software was coded during the GSoC 2011'))
  382.         w.set_logo(gtk.gdk.pixbuf_new_from_file_at_size(self.logo, 400, 200))
  383.         w.set_program_name('Metadata Anonymisation Toolkit')
  384.         w.set_version(mat.__version__)
  385.         w.set_website('https://mat.boum.org')
  386.         w.set_website_label(_('Website'))
  387.         w.set_position(gtk.WIN_POS_CENTER)
  388.         w.run()
  389.         w.destroy()
  390.  
  391.     def __supported(self, button):
  392.         '''
  393.             List the supported formats
  394.         '''
  395.         dialog = gtk.Dialog(_('Supported formats'), self.window, 0,
  396.             (gtk.STOCK_CLOSE, 0))
  397.         vbox = gtk.VBox(spacing=5)
  398.         dialog.get_content_area().pack_start(vbox, True, True, 0)
  399.  
  400.         label = gtk.Label()
  401.         label.set_markup('<big><u>Supported fileformats</u></big>')
  402.         vbox.pack_start(label, True, True, 0)
  403.  
  404.         #parsing xml
  405.         handler = mat.XMLParser()
  406.         parser = xml.sax.make_parser()
  407.         parser.setContentHandler(handler)
  408.         path = mat.get_sharedir('FORMATS')
  409.         with open(path, 'r') as xmlfile:
  410.             parser.parse(xmlfile)
  411.  
  412.         def expander_callback(current):
  413.             ''' Close every expander except the current one '''
  414.             for i in vbox.get_children()[1:]:  # first child is a gtk.Label
  415.                 if i != current:
  416.                     i.set_expanded(False)
  417.  
  418.         for item in handler.list:  # list of dict : one dict per format
  419.             # create one expander per format
  420.             # only if the format is supported
  421.             if item['mimetype'].split(',')[0] in strippers.STRIPPERS:
  422.                 # some format have more than one mimetype
  423.                 title = '%s (%s)' % (item['name'], item['extension'])
  424.                 support = ('\t<b>%s</b> : %s' % ('support', item['support']))
  425.                 metadata = '\n\t<b>metadata</b> : ' + item['metadata']
  426.                 method = '\n\t<b>method</b> : ' + item['method']
  427.                 content = support + metadata + method
  428.                 if item['support'] == 'partial':
  429.                     content += '\n\t<b>remaining</b> : ' + item['remaining']
  430.  
  431.                 expander = gtk.Expander(title)
  432.                 vbox.pack_start(expander, False, False, 0)
  433.                 label = gtk.Label()
  434.                 label.set_markup(content)
  435.                 expander.add(label)
  436.                 expander.connect('activate', expander_callback)
  437.  
  438.         dialog.show_all()
  439.         click = dialog.run()
  440.         if click is 0:  # Close
  441.             dialog.destroy()
  442.  
  443.     def __preferences(self, button):
  444.         '''
  445.             Preferences popup
  446.         '''
  447.         dialog = gtk.Dialog(_('Preferences'), self.window, 0,
  448.                 (gtk.STOCK_OK, 0))
  449.         hbox = gtk.HBox()
  450.         dialog.get_content_area().pack_start(hbox, False, False, 0)
  451.  
  452.         icon = gtk.Image()
  453.         icon.set_from_stock(gtk.STOCK_PREFERENCES, gtk.ICON_SIZE_DIALOG)
  454.         hbox.pack_start(icon, False, False, 20)
  455.  
  456.         table = gtk.Table(3, 2, False)  # nb rows, nb lines
  457.         hbox.pack_start(table, True, True, 0)
  458.  
  459.         force = gtk.CheckButton(_('Force Clean'), False)
  460.         force.set_active(self.force)
  461.         force.connect('toggled', self.__invert, 'force')
  462.         force.set_tooltip_text(_('Do not check if already clean before \
  463. cleaning'))
  464.         table.attach(force, 0, 1, 0, 1)
  465.  
  466.         backup = gtk.CheckButton(_('Backup'), False)
  467.         backup.set_active(self.backup)
  468.         backup.connect('toggled', self.__invert, 'backup')
  469.         backup.set_tooltip_text(_('Keep a backup copy'))
  470.         table.attach(backup, 0, 1, 1, 2)
  471.  
  472.         add2archive = gtk.CheckButton(_('Add unsupported file to archives'),
  473.             False)
  474.         add2archive.set_active(self.add2archive)
  475.         add2archive.connect('toggled', self.__invert, 'add2archive')
  476.         add2archive.set_tooltip_text(_('Add non-supported (and so \
  477. non-anonymised) file to output archive'))
  478.         table.attach(add2archive, 0, 1, 2, 3)
  479.  
  480.         hbox.show_all()
  481.         response = dialog.run()
  482.         if response is 0:  # gtk.STOCK_OK
  483.             dialog.destroy()
  484.  
  485.     def __invert(self, button, name):
  486.         '''
  487.             Invert a preference state
  488.         '''
  489.         if name == 'force':
  490.             self.force = not self.force
  491.         elif name == 'backup':
  492.             self.backup = not self.backup
  493.             for line in xrange(len(self.liststore)):
  494.                 # change the "backup" property of all files
  495.                 self.liststore[line][0].file.backup = self.backup
  496.             self.treeview.get_column(4).set_visible(self.backup)
  497.         elif name == 'add2archive':
  498.             self.add2archive = not self.add2archive
  499.  
  500.     def __on_drag_data_received(self, widget, context,
  501.             x, y, selection, target_type, timestamp):
  502.         '''
  503.             This function is called when something is
  504.             drag'n'droped into mat.
  505.             It basically add files.
  506.         '''
  507.         urls = selection.data.strip('\r\n\x00')  # strip stupid characters
  508.         cleaned_urls = map(self.__clean_draged_file_path, urls.split('\n'))
  509.         task = self.populate(cleaned_urls)
  510.         gobject.idle_add(task.next)  # asynchrone processing
  511.  
  512.     def __clean_draged_file_path(self, url):
  513.         '''
  514.             Since the dragged urls are ugly,
  515.             we need to process them
  516.         '''
  517.         url = urllib2.unquote(url)  # unescape stupid chars
  518.         if url.startswith('file:\\\\\\'):  # windows
  519.             return url[8:]  # 8 is len('file:///')
  520.         elif url.startswith('file://'):  # nautilus, rox
  521.             return url[7:]  # 7 is len('file://')
  522.         elif url.startswith('file:'):  # xffm
  523.             return url[5:]  # 5 is len('file:')
  524.  
  525.     def __process_files(self, button, func):
  526.         '''
  527.             Launch the function "func" in a asynchrone way
  528.         '''
  529.         iterator = self.selection.get_selected_rows()[1]
  530.         if not iterator:  # if nothing is selected : select everything
  531.             iterator = xrange(len(self.liststore))
  532.         task = func(iterator)  # launch func() in an asynchrone way
  533.         gobject.idle_add(task.next)
  534.  
  535.     def __mat_check(self, iterator):
  536.         '''
  537.             Check if selected elements are clean
  538.         '''
  539.         for line in iterator:  # for each file in selection
  540.             self.statusbar.push(0, _('Checking %s...') % self.liststore[line][1])
  541.             if self.force is True or self.liststore[line][4] != _('Clean'):
  542.                 if self.liststore[line][0].file.is_clean():
  543.                     string = _('Clean')
  544.                 else:
  545.                     string = _('Dirty')
  546.                 logging.info('%s is %s' % (self.liststore[line][1], string))
  547.                 self.liststore[line][4] = string
  548.                 yield True
  549.         self.statusbar.push(0, _('Ready'))
  550.         yield False
  551.  
  552.     def __mat_clean(self, iterator):
  553.         '''
  554.             Clean selected elements
  555.         '''
  556.         for line in iterator:  # for each file in selection
  557.             logging.info('Cleaning %s' % self.liststore[line][1])
  558.             self.statusbar.push(0, _('Cleaning %s...') % self.liststore[line][1])
  559.             if self.force is True or self.liststore[line][4] != _('Clean'):
  560.                 if self.liststore[line][0].file.remove_all():
  561.                     self.liststore[line][4] = _('Clean')
  562.                     if self.backup:  # the backup copy state
  563.                         self.liststore[line][5] = os.path.basename(self.liststore[line][0].file.output)
  564.             yield True
  565.         self.statusbar.push(0, _('Ready'))
  566.         yield False
  567.  
  568. if __name__ == '__main__':
  569.     gettext.install('MAT', unicode=True)
  570.  
  571.     #Main
  572.     gui = GUI()
  573.  
  574.     #Add files from command line
  575.     infiles = [arg for arg in sys.argv[1:] if os.path.exists(arg)]
  576.     if infiles:
  577.         task = gui.populate(infiles)
  578.         gobject.idle_add(task.next)
  579.  
  580.     gtk.main()
  581.